package cn.stacey.day13;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//两个线程,用线程池 ArrayList是线程不安全
//几个线程同时改同一个对象eggs,eggs对象可能会越界,
//用synchronized（放在buy()和put()方法），每次进一个线程，另一个在外面等,
//另外一种synchronized写法不是放在buy前面，而是synchronized（eggs）{}
//但是这种方法使用wait()时，释放的是鸡蛋对象，再用notityAll()唤醒时会有问题
public class ProducerConsumer {
	public static void main(String[] args) {
		ExecutorService server = Executors.newFixedThreadPool(10);
		Factory factory = new Factory();
		server.execute(new Producer(factory));
		server.execute(new Consumer(factory));
		server.shutdown();

	}
}
class Producer implements Runnable {
	private Factory factory;

	public Producer(Factory f) {
		// TODO Auto-generated constructor stub
		this.factory = f;
	}

	@Override
	public void run() {

		try {
			while (true) {
				factory.put();
				Thread.sleep((long) (Math.random() * 100));
			}

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	// TODO Auto-generated method stub

}

class Consumer implements Runnable {
	private Factory factory;

	public Consumer(Factory f) {
		this.factory = f;
	}

	@Override
	public void run() {
		try {
			while (true) {
				// 每次从工厂取一个鸡蛋
				factory.buy();

				Thread.sleep((long) (Math.random() * 100));
			}

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

class Factory {
	private static final int MAX = 10;
	List<Integer> eggs = new ArrayList<>();
	int id = 1;

	// 被人消费一个产品
	// synchronized给对象加上了锁，在方法上写synchronized相当于给Factory对象加了一个锁
	// 第二种方法在eggs对象上加锁，别人都进不来
	public synchronized void buy() {
		// 另外一种synchronized写法不是放在buy前面，而是synchronized（eggs）{}
		// 但是这种方法使用wait()时，释放的是鸡蛋对象，再用notityAll()唤醒时会有问题

		if (eggs.size() == 0) {
			System.out.println("鸡蛋卖完了。。。白跑一趟");
			try {
				wait();// 当前线程处于等待状态
				// 但是消费者不能一直在等，不然生产者放鸡蛋进去了也不知道
				// notifyAll()唤醒会释放锁，让其他线程也进来，这时候突然生产者放了一个鸡蛋进去，几个消费则会同时买鸡蛋就会报错
				// 所以后面要判断
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// 同时有多个消费者时才需要下面这句话，但一般情况都是一个生产者一个消费者
		if (eggs.size() == 0)
			return;

		Integer last = eggs.remove(eggs.size() - 1);
		System.out.println("买到一个鸡蛋" + last);
		// 叫醒其他处于等待的线程
		notifyAll();
	}

	// 生产一个产品
	public synchronized void put() {

		if (eggs.size() >= MAX) {
			System.out.println("放不下了。。。鸡蛋扔掉吧");
			try {
				System.out.println("等等吧总会有人买的");
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

		System.out.println("放入了一个鸡蛋" + id);
		eggs.add(id++);
		// 叫醒其他处于等待的线程
		notifyAll();
	}
}
